#include "mem_pool.h"
#include "res_queue.h"
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define MIN_BLOCK_SIZE 8
#define MAX_BLOCK_SIZE 1024
#define NUM_BLOCK_TYPES 8   // 8,16,32...1024
#define POOL_UNIT_SIZE 2048 // 每个内存单元块大小

#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
  
enum {
    block_size_8,
    block_size_16,
    block_size_32,
    block_size_64,
    block_size_128,
    block_size_256,
    block_size_512,
    block_size_1024,
};

typedef struct {
    res_queue_t* queues[NUM_BLOCK_TYPES];   // 不同块类型的队列
    char* memory_chunk;                     // 内存池起始地址
    size_t total_size;                      // 内存池总大小
    int initialized;                        // 初始化标记
} memery_pool_t;

static memery_pool_t g_mem_pool_mgr;

int mem_pool_init(size_t total_size) 
{
    // input check
    if (g_mem_pool_mgr.initialized) return -1;
    if (total_size & (POOL_UNIT_SIZE - 1)) {
        printf("[%s][%d] total_size must be an integer multiple of %d\n", __FUNCTION__, __LINE__, POOL_UNIT_SIZE);
        return -1;
    }
    
    // 单元数
    int units = total_size / POOL_UNIT_SIZE;
    int i = 0;
	
    // 分配内存区域
    g_mem_pool_mgr.memory_chunk = (char*)aligned_alloc(POOL_UNIT_SIZE, total_size);
    if (g_mem_pool_mgr.memory_chunk == NULL) {
        return -1;
    }
    
    // 初始化 queues[NUM_BLOCK_TYPES]
    for (i = 0; i < NUM_BLOCK_TYPES; i++) {
        g_mem_pool_mgr.queues[i] = queue_res_init(units);
        if (g_mem_pool_mgr.queues[i] == NULL) {
            goto error_queue_init;
        }
    }
	
    g_mem_pool_mgr.total_size = total_size;
    g_mem_pool_mgr.initialized = 1;

	printf("[%s][%d] init sucess start_ptr=%p\n", __FUNCTION__, __LINE__, g_mem_pool_mgr.memory_chunk);
    return 0;
    
error_queue_init:
    
    while (i >= 0) {
        if (g_mem_pool_mgr.queues[i]) {
            free(g_mem_pool_mgr.queues[i]);
            g_mem_pool_mgr.queues[i] = NULL;
        }
        i--;
    }

	if (g_mem_pool_mgr.memory_chunk) {
		free(g_mem_pool_mgr.memory_chunk);
		g_mem_pool_mgr.memory_chunk = NULL;
	}
		
    return -1;
}

void* mem_pool_alloc(size_t size) 
{
    if (unlikely(!g_mem_pool_mgr.initialized || size > MAX_BLOCK_SIZE || size == 0))
        return NULL;
    
	int size_type = -1;
	unsigned int uint_index = -1;
	
	// 不用while，提高效率
	switch (size) {
		case 0x001 ... 0x008: size_type = block_size_8;   break;
		case 0x009 ... 0x010: size_type = block_size_16;  break;
		case 0x011 ... 0x020: size_type = block_size_32;  break;
		case 0x021 ... 0x040: size_type = block_size_64;  break;
		case 0x041 ... 0x080: size_type = block_size_128; break;
		case 0x081 ... 0x100: size_type = block_size_256; break;
		case 0x101 ... 0x200: size_type = block_size_512; break;
		case 0x201 ... 0x400: size_type = block_size_1024;break;
	}

	// 如果当前size的资源已经用完，尝试借用资源
	do { uint_index = queue_res_apply(g_mem_pool_mgr.queues[size_type]);
	} while (unlikely(uint_index == -1 && size_type++ < NUM_BLOCK_TYPES));
	
	if (uint_index == -1) return NULL;

	//printf("[%s][%d]alloc size_type=%d, unit_idx=%d ptr=%p\n", __FUNCTION__, __LINE__, size_type, uint_index, 
    //g_mem_pool_mgr.memory_chunk + (uint_index*POOL_UNIT_SIZE) + (8<<size_type));
    return g_mem_pool_mgr.memory_chunk + ((uint_index<<11) | (8<<size_type));
}

void mem_pool_free(void* ptr) 
{
    if (unlikely(!g_mem_pool_mgr.initialized || !ptr)) return;
    
    size_t size = (size_t)ptr & 0x7FF;
	int size_type = -1;
	// 不用while，提高效率
	switch (size) {
		case 0x008: size_type = block_size_8;   break;
		case 0x010: size_type = block_size_16;  break;
		case 0x020:	size_type = block_size_32;  break;
		case 0x040:	size_type = block_size_64;  break;
		case 0x080:	size_type = block_size_128; break;
		case 0x100:	size_type = block_size_256; break;
		case 0x200: size_type = block_size_512; break;
		case 0x400:	size_type = block_size_1024;break;
	}
    
	if (unlikely(size_type == -1)) {
        printf("[%s][%d] ptr=%p size=%lu size_type=%d unit_idx=%ld\n", __FUNCTION__, __LINE__, 
               ptr, size, size_type, ((char*)ptr - g_mem_pool_mgr.memory_chunk)>>11);
        return;
    }
	queue_res_release(g_mem_pool_mgr.queues[size_type], ((char*)ptr - g_mem_pool_mgr.memory_chunk)>>11);
	
	return;
}

void mem_pool_show() 
{
    if (unlikely(!g_mem_pool_mgr.initialized)) return;
    
    for (int i = 0; i < NUM_BLOCK_TYPES; i++) {
        dump_res_queue(g_mem_pool_mgr.queues[i]);
    }
	
	return;
}

void mem_pool_destroy() 
{
    if (!g_mem_pool_mgr.initialized) return;
	
	int i = 0;
    for (i = 0; i < NUM_BLOCK_TYPES; i++) {
        if (g_mem_pool_mgr.queues[i]) {
            free(g_mem_pool_mgr.queues[i]);
			g_mem_pool_mgr.queues[i] = NULL;
        }
    }

	free(g_mem_pool_mgr.memory_chunk);
	g_mem_pool_mgr.memory_chunk = NULL;
	g_mem_pool_mgr.total_size = 0;
    g_mem_pool_mgr.initialized = 0;
}